/**
 * 数据脱敏模块
 * 用于对敏感信息进行脱敏处理，如密码、邮箱、手机号等
 */

// 从统一配置模块获取日志配置
const config = require('../../config');

// 默认脱敏配置
const DEFAULT_SENSITIZATION_CONFIG = {
  password: { pattern: /"password":"[^"]*"/gi, replace: '"password":"***"' },
  token: { pattern: /"token":"[^"]*"/gi, replace: '"token":"***"' },
  email: { pattern: /([\w.-]+)@([\w.-]+\.[\w.-]+)/gi, replace: (match, p1, p2) => `${p1.slice(0, 2)}****@${p2}` },
  phone: { pattern: /1[3-9]\d{9}/gi, replace: (match) => `${match.slice(0, 3)}****${match.slice(7)}` },
  idCard: { pattern: /(\d{6})\d{8}(\d{4})/gi, replace: '$1********$2' },
  bankCard: { pattern: /(\d{4})\d{8,12}(\d{4})/gi, replace: '$1********$2' }
};

// 使用配置中的脱敏设置，如果没有则使用默认配置
const SENSITIZATION_CONFIG = config.logger?.SENSITIZATION_CONFIG || DEFAULT_SENSITIZATION_CONFIG;

/**
 * 数据脱敏工具类
 * 负责对日志中的敏感信息进行脱敏处理
 */
class DataMasker {
  constructor(config = SENSITIZATION_CONFIG) {
    this.config = config;
  }

  /**
   * 对字符串进行脱敏处理
   * @param {string} data - 待脱敏的数据
   * @returns {string} - 脱敏后的数据
   */
  mask(data) {
    if (!data || typeof data !== 'string') {
      return data;
    }

    let maskedData = data;

    // 应用所有脱敏规则
    Object.values(this.config).forEach(({ pattern, replace }) => {
      maskedData = maskedData.replace(pattern, replace);
    });

    return maskedData;
  }

  /**
   * 检查字段是否为敏感字段
   * @param {string} fieldName - 字段名
   * @returns {boolean} - 是否为敏感字段
   */
  isSensitiveField(fieldName) {
    if (!fieldName) return false;
    
    // 标准化字段名（移除驼峰或蛇形命名差异）
    const normalizedField = fieldName.toLowerCase();
    
    // 检查常见的敏感字段名
    const sensitiveKeywords = [
      'password', 'token', 'secret', 'key', 'api',
      'email', 'phone', 'tel', 'mobile', 'idcard', '身份证',
      'bank', 'credit', 'card', 'account', 'accountnumber',
      'auth', 'authorization', 'access'
    ];
    
    return sensitiveKeywords.some(keyword => normalizedField.includes(keyword));
  }

  /**
   * 对对象进行脱敏处理
   * @param {object} obj - 待脱敏的对象
   * @returns {object} - 脱敏后的对象（深拷贝）
   */
  maskObject(obj) {
    if (!obj || typeof obj !== 'object') {
      return obj;
    }

    try {
      // 转换为字符串进行脱敏，然后转换回对象
      const jsonString = JSON.stringify(obj);
      const maskedString = this.mask(jsonString);
      return JSON.parse(maskedString);
    } catch (error) {
      // 如果序列化/反序列化失败，尝试安全地序列化错误对象
      console.error('数据脱敏失败:', error);
      
      // 对于错误对象，尝试提取安全的属性
      if (obj instanceof Error) {
        const safeError = {
          message: obj.message,
          name: obj.name,
          code: obj.code,
          errno: obj.errno,
          status: obj.status,
          statusCode: obj.statusCode
        };
        
        // 移除undefined属性
        Object.keys(safeError).forEach(key => {
          if (safeError[key] === undefined) {
            delete safeError[key];
          }
        });
        
        return safeError;
      }
      
      // 对于其他对象，尝试递归清理循环引用
      const seen = new WeakSet();
      const cleanObj = JSON.parse(JSON.stringify(obj, (key, value) => {
        if (typeof value === 'object' && value !== null) {
          // 检测循环引用
          if (seen.has(value)) {
            return '[Circular]';
          }
          seen.add(value);
        }
        return value;
      }));
      
      return cleanObj;
    }
  }

  /**
   * 测试数据脱敏功能（用于单元测试）
   * @param {object} testData - 测试数据
   * @returns {object} - 包含原始数据、脱敏数据和验证结果的对象
   */
  testMasking(testData) {
    const originalData = JSON.stringify(testData);
    const maskedData = this.mask(originalData);
    
    // 验证密码是否被脱敏
    const passwordMasked = !maskedData.includes('"password":"secret123"');
    // 验证令牌是否被脱敏
    const tokenMasked = !maskedData.includes('"token":"jwt_token_secret"');
    // 验证邮箱是否被脱敏
    const emailMasked = maskedData.includes('"email":"us****@example.com"');
    // 验证手机号是否被脱敏
    const phoneMasked = maskedData.includes('"phone":"138****8888"');
    // 验证ID卡是否被脱敏
    const idCardMasked = maskedData.includes('"idCard":"123456********1234"');
    // 验证银行卡是否被脱敏
    const bankCardMasked = maskedData.includes('"bankCard":"1234********5678"');
    
    // 验证非敏感字段是否保持不变
    const nonSensitivePreserved = maskedData.includes('"name":"John Doe"');
    
    return {
      originalData,
      maskedData,
      results: {
        passwordMasked,
        tokenMasked,
        emailMasked,
        phoneMasked,
        idCardMasked,
        bankCardMasked,
        nonSensitivePreserved,
        allPass: passwordMasked && tokenMasked && emailMasked && phoneMasked && 
                 idCardMasked && bankCardMasked && nonSensitivePreserved
      }
    };
  }
}

module.exports = {
  DataMasker,
  SENSITIZATION_CONFIG,
  // 便捷方法：直接对数据进行脱敏
  mask: (data) => new DataMasker().mask(data),
  // 便捷方法：直接对对象进行脱敏
  maskObject: (obj) => new DataMasker().maskObject(obj),
  // 便捷方法：测试脱敏功能
  testDataMasking: (testData) => new DataMasker().testMasking(testData)
};